package com.shen.forkjoin;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
import java.util.stream.LongStream;

public class ForkJoinDemo extends RecursiveTask<Long> {
    private Long start;//开始值
    private Long end;//结束值
    private Long temp=10000L;//临界值

    public ForkJoinDemo(Long start, Long end) {
        this.start = start;
        this.end = end;
    }

    /**
     * 计算方法
     * @return
     */
    @Override
    protected Long compute() {
        if((end-start)<temp){

            Long sum=0L;//计算结果
            for (Long i=start;i<=end;i++){
                sum=sum+i;
            }
            return sum;
        }else{
            //合并分支计算
            //拆分任务
            long middle =(start+end)/2;

            /**
             * 这里有一个递归，主要目的是拆分任务
             */
            ForkJoinDemo task1 = new ForkJoinDemo(start, middle);
            task1.fork();//在当前线程池中安排一个异步执行

            ForkJoinDemo task2=new ForkJoinDemo(middle+1,end);
            task2.fork();

            return task1.join() + task2.join();

        }
    }
}

/**
 * 测试
 */
class Test{
    public static void main(String[] args) {
       // test();//sum=500000000500000000，完成时间：10494
        //test02();//sum=500000000500000000，完成时间：7479
        test03();//sum=500000000500000000，完成时间：785
    }

    /**
     * 普通方式加减
     */
    public static void test(){
        Long startTime=System.currentTimeMillis();

        Long sum=0L;//计算结果
        for (Long i=1L;i<=10_0000_0000;i++){
            sum=sum+i;
        }
        Long endTime=System.currentTimeMillis();
        System.out.println("sum="+sum+"，完成时间："+(endTime-startTime));
    }

    /**
     * ForkJoin
     */
    public static void test02(){
        Long startTime=System.currentTimeMillis();
        Long sum=0L;//计算结果

        ForkJoinPool forkJoinPool = new ForkJoinPool();

        ForkJoinDemo task=new ForkJoinDemo(0L,10_0000_0000L);

        //execute() 同步提交任务方式
        //submit()  异步的提交任务方式
        //submit会返回ForkJoinTask，而execute不会
        ForkJoinTask<Long> submit = forkJoinPool.submit(task);


        try {
           sum= submit.get();//获得结果值
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        Long endTime=System.currentTimeMillis();
        System.out.println("sum="+sum+"，完成时间："+(endTime-startTime));
    }


    /**
     * 并行流
     */
    public static void test03(){
        Long startTime=System.currentTimeMillis();
        Long sum=LongStream.rangeClosed(0L,10_0000_0000L).parallel().reduce(0,Long::sum);
        Long endTime=System.currentTimeMillis();
        System.out.println("sum="+sum+"，完成时间："+(endTime-startTime));
    }

}
